home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 June: Reference Library / Dev.CD Jun 94.toast / Periodicals / develop / develop Issue 10 / develop 10 code / GWorld Drawing / GWorld Routines / xform bitmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-08  |  16.6 KB  |  572 lines  |  [TEXT/KAHL]

  1. #include "DemoRoutines.h"
  2. #include "math.h"
  3. #include "xform bitmap.h"
  4.  
  5. #define use_box_filter     1
  6.  
  7. void Assert(int assertion)
  8. {
  9.     if (!assertion)
  10.         Debugger();
  11. }
  12.  
  13. shortFrac ShortFracMul(shortFrac a, shortFrac b)
  14. {
  15.     return (long)a * b + halfShortFrac >> 14;
  16. }
  17.  
  18. unsigned char ShortFracMulByte(shortFrac percent, unsigned char value)
  19. {
  20.     return ShortFracMul(percent, value);
  21. }
  22.  
  23. Boolean ModelessPtInRect(Point p, Rect* r)
  24. {
  25.     return p.h < r->right && p.h >= r->left && p.v < r->bottom && p.v >= r->top;
  26. }
  27.  
  28. /*    This uses a 2x2 box filter with the coord at the upper left
  29.   *
  30.   *    1    1
  31.   *    1    1
  32.   */
  33.  
  34.  /*  !!!! Note: it is illegal to call trap calls in this routine (that's why we use the ModelessPtInRect routine below). The 
  35.  caller needs to swap modes to 32 bit before calling this routine, and making trap calls in that state could crash the 
  36.  computer !!!! */
  37.  
  38. Boolean GetFractionalPixel(long* srcBaseAddr, long srcRowLongs, Rect* srcBounds, Fixed fx, Fixed fy, long* dstLong )
  39. {
  40.     unsigned long    tempBlue, tempGreen, tempRed;
  41.     long            srcPixel[2][2];
  42.     shortFrac        scale[2][2];
  43.     Point            p;
  44.     
  45.     SetPt(&p, fx >> 16, fy >> 16);
  46.     if (!ModelessPtInRect(p, srcBounds))
  47.         return false;
  48.  
  49.     if (p.h == srcBounds->right - 1)
  50.         fx = ff(p.h);
  51.     if (p.v == srcBounds->bottom - 1)
  52.         fy = ff(p.v);
  53.  
  54.     /*    Compute the addr of the first src pixel
  55.     */
  56.     {    
  57.         long* srcAddr = srcBaseAddr + p.v * srcRowLongs + p.h;
  58.  
  59. #if use_box_filter
  60.         *dstLong = *srcAddr;
  61.         return true;
  62. #endif
  63.         srcPixel[0][0] = *srcAddr++;
  64.         srcPixel[0][1] = *srcAddr++;
  65.         srcAddr += srcRowLongs;
  66.         srcPixel[1][1] = *--srcAddr;
  67.         srcPixel[1][0] = *--srcAddr;
  68.     }
  69.  
  70.     /*    Precompute the scales for each pixel
  71.     */
  72.     {    shortFrac xFrac = Fixed2ShortFrac((unsigned short)fx);
  73.         shortFrac yFrac = Fixed2ShortFrac((unsigned short)fy);
  74.     
  75.         scale[0][0] = ShortFracMul(oneShortFrac - xFrac, oneShortFrac - yFrac);
  76.         scale[0][1] = ShortFracMul(xFrac, oneShortFrac - yFrac);
  77.         scale[1][0] = ShortFracMul(oneShortFrac - xFrac, yFrac);
  78.         scale[1][1] = ShortFracMul(xFrac, yFrac);
  79.     }
  80.  
  81. /*
  82.   *    Now scale each component of each corner by the percentage coverage by the filter
  83.   */
  84.     tempBlue =    ShortFracMulByte(scale[0][0], srcPixel[0][0]) +
  85.                 ShortFracMulByte(scale[0][1], srcPixel[0][1]) +
  86.                 ShortFracMulByte(scale[1][0], srcPixel[1][0]) +
  87.                 ShortFracMulByte(scale[1][1], srcPixel[1][1]);
  88.     if (tempBlue == 256) tempBlue = 255;
  89.     Assert(tempBlue >= 0 && tempBlue < 256);
  90.     
  91.     tempGreen =    ShortFracMulByte(scale[0][0], srcPixel[0][0] >> 8) +
  92.                 ShortFracMulByte(scale[0][1], srcPixel[0][1] >> 8) +
  93.                 ShortFracMulByte(scale[1][0], srcPixel[1][0] >> 8) +
  94.                 ShortFracMulByte(scale[1][1], srcPixel[1][1] >> 8);
  95.     if (tempGreen == 256) tempGreen = 255;
  96.     Assert(tempGreen >= 0 && tempGreen < 256);
  97.     
  98.     tempRed =        ShortFracMulByte(scale[0][0], srcPixel[0][0] >> 16) +
  99.                 ShortFracMulByte(scale[0][1], srcPixel[0][1] >> 16) +
  100.                 ShortFracMulByte(scale[1][0], srcPixel[1][0] >> 16) +
  101.                 ShortFracMulByte(scale[1][1], srcPixel[1][1] >> 16);
  102.     if (tempRed == 256) tempRed = 255;
  103.     Assert(tempRed >= 0 && tempRed < 256);
  104.  
  105.     *dstLong = (tempRed << 16) | (tempGreen << 8) | tempBlue;
  106.     return true;
  107. }
  108.  
  109.  
  110. /*    This uses a 2x2 box filter with the coord at the upper left
  111.   *
  112.   *    1    1
  113.   *    1    1
  114.   */
  115.  
  116.  /*  !!!! Note: it is illegal to call trap calls in this routine (that's why we use the ModelessPtInRect routine below). The 
  117.  caller needs to swap modes to 32 bit before calling this routine, and making trap calls in that state could crash the 
  118.  computer !!!! */
  119.  
  120. /* Editor's Note: I modified this routine to always use the box filter, for demo purposes. There's a similar routine
  121. below that uses only the tent filter, and above is the more general routine that's in the article */
  122. Boolean GetFractionalPixelBox(long* srcBaseAddr, long srcRowLongs, Rect* srcBounds, Fixed fx, Fixed fy, long* dstLong )
  123. {
  124.     unsigned long    tempBlue, tempGreen, tempRed;
  125.     long            srcPixel[2][2];
  126.     shortFrac        scale[2][2];
  127.     Point            p;
  128.     
  129.     SetPt(&p, fx >> 16, fy >> 16);
  130.     if (!ModelessPtInRect(p, srcBounds))
  131.         return false;
  132.  
  133.     if (p.h == srcBounds->right - 1)
  134.         fx = ff(p.h);
  135.     if (p.v == srcBounds->bottom - 1)
  136.         fy = ff(p.v);
  137.  
  138.     /*    Compute the addr of the first src pixel
  139.     */
  140.     {    
  141.         long* srcAddr = srcBaseAddr + p.v * srcRowLongs + p.h;
  142.  
  143.         *dstLong = *srcAddr;
  144.         return true;
  145.     }
  146. }
  147.  
  148. /*    This uses a 2x2 box filter with the coord at the upper left
  149.   *
  150.   *    1    1
  151.   *    1    1
  152.   */
  153.  
  154.  /*  !!!! Note: it is illegal to call trap calls in this routine (that's why we use the ModelessPtInRect routine below). The 
  155.  caller needs to swap modes to 32 bit before calling this routine, and making trap calls in that state could crash the 
  156.  computer !!!! */
  157.  
  158. /* Editor's Note: I modified this routine to always use the tent filter, for demo purposes. There's a similar routine
  159. above that uses only the box filter, and above that is the more general routine that's in the article */
  160. Boolean GetFractionalPixelTent(long* srcBaseAddr, long srcRowLongs, Rect* srcBounds, Fixed fx, Fixed fy, long* dstLong )
  161. {
  162.     unsigned long    tempBlue, tempGreen, tempRed;
  163.     long            srcPixel[2][2];
  164.     shortFrac        scale[2][2];
  165.     Point            p;
  166.     
  167.     SetPt(&p, fx >> 16, fy >> 16);
  168.     if (!ModelessPtInRect(p, srcBounds))
  169.         return false;
  170.  
  171.     if (p.h == srcBounds->right - 1)
  172.         fx = ff(p.h);
  173.     if (p.v == srcBounds->bottom - 1)
  174.         fy = ff(p.v);
  175.  
  176.     /*    Compute the addr of the first src pixel
  177.     */
  178.     {    
  179.         long* srcAddr = srcBaseAddr + p.v * srcRowLongs + p.h;
  180.  
  181.         srcPixel[0][0] = *srcAddr++;
  182.         srcPixel[0][1] = *srcAddr++;
  183.         srcAddr += srcRowLongs;
  184.         srcPixel[1][1] = *--srcAddr;
  185.         srcPixel[1][0] = *--srcAddr;
  186.     }
  187.  
  188.     /*    Precompute the scales for each pixel
  189.     */
  190.     {    shortFrac xFrac = Fixed2ShortFrac((unsigned short)fx);
  191.         shortFrac yFrac = Fixed2ShortFrac((unsigned short)fy);
  192.     
  193.         scale[0][0] = ShortFracMul(oneShortFrac - xFrac, oneShortFrac - yFrac);
  194.         scale[0][1] = ShortFracMul(xFrac, oneShortFrac - yFrac);
  195.         scale[1][0] = ShortFracMul(oneShortFrac - xFrac, yFrac);
  196.         scale[1][1] = ShortFracMul(xFrac, yFrac);
  197.     }
  198.  
  199. /*
  200.   *    Now scale each component of each corner by the percentage coverage by the filter
  201.   */
  202.     tempBlue =    ShortFracMulByte(scale[0][0], srcPixel[0][0]) +
  203.                 ShortFracMulByte(scale[0][1], srcPixel[0][1]) +
  204.                 ShortFracMulByte(scale[1][0], srcPixel[1][0]) +
  205.                 ShortFracMulByte(scale[1][1], srcPixel[1][1]);
  206.     if (tempBlue == 256) tempBlue = 255;
  207.     Assert(tempBlue >= 0 && tempBlue < 256);
  208.     
  209.     tempGreen =    ShortFracMulByte(scale[0][0], srcPixel[0][0] >> 8) +
  210.                 ShortFracMulByte(scale[0][1], srcPixel[0][1] >> 8) +
  211.                 ShortFracMulByte(scale[1][0], srcPixel[1][0] >> 8) +
  212.                 ShortFracMulByte(scale[1][1], srcPixel[1][1] >> 8);
  213.     if (tempGreen == 256) tempGreen = 255;
  214.     Assert(tempGreen >= 0 && tempGreen < 256);
  215.     
  216.     tempRed =        ShortFracMulByte(scale[0][0], srcPixel[0][0] >> 16) +
  217.                 ShortFracMulByte(scale[0][1], srcPixel[0][1] >> 16) +
  218.                 ShortFracMulByte(scale[1][0], srcPixel[1][0] >> 16) +
  219.                 ShortFracMulByte(scale[1][1], srcPixel[1][1] >> 16);
  220.     if (tempRed == 256) tempRed = 255;
  221.     Assert(tempRed >= 0 && tempRed < 256);
  222.  
  223.     *dstLong = (tempRed << 16) | (tempGreen << 8) | tempBlue;
  224.     return true;
  225. }
  226.  
  227. LockGWorldPixels(GWorldPtr world, Boolean lockIt)
  228. {
  229.     if (lockIt)
  230.         LockPixels(GetGWorldPixMap(world));
  231.     else
  232.         UnlockPixels(GetGWorldPixMap(world));
  233. }
  234.  
  235. void SetGWorldPixel(GWorldPtr world, short x, short y)
  236. {
  237.     GDHandle oldGD;
  238.     GWorldPtr oldGW;
  239.  
  240.     GetGWorld(&oldGW,&oldGD);
  241.     SetGWorld(world, nil);
  242.     LockGWorldPixels(world, true);
  243.     MoveTo(x, y);
  244.     LineTo(x, y);
  245.     LockGWorldPixels(world, false);
  246.     SetGWorld(oldGW,oldGD);
  247. }
  248.  
  249. void EraseGWorld( GWorldPtr world, Rect* bounds )
  250. {
  251.     GDHandle oldGD;
  252.     GWorldPtr oldGW;
  253.  
  254.     GetGWorld(&oldGW,&oldGD);
  255.     SetGWorld(world, nil);
  256.     LockGWorldPixels(world, true);
  257.     EraseRect( bounds );
  258.     LockGWorldPixels(world, false);
  259.     SetGWorld(oldGW,oldGD);
  260. }
  261.  
  262. void FancyMap(const Rect* srcRect, Fixed* xPtr, Fixed* yPtr)
  263. {
  264.     double x = *xPtr / 65536.0;
  265.     double dx = 2 * 3.1415926 * (x - (srcRect->right + srcRect->left >> 1)) / (srcRect->right - srcRect->left);
  266.     double amp = srcRect->right - srcRect->left >> 3;
  267.     double delta = sin(dx) * amp;
  268.  
  269.     *yPtr += delta * 65536.0;
  270. }
  271.  
  272. void FancyMapBounds(Rect* bounds)
  273. {
  274.     short width = bounds->right - bounds->left;
  275.     short height = bounds->bottom - bounds->top;
  276.  
  277.     bounds->top -= width >> 3;
  278.     bounds->bottom += width >> 3;
  279. }
  280.  
  281. GWorldPtr MapGWorld(GWorldPtr srcWorld, mapping* dstMapping, GWorldPtr* maskWorld)
  282. {
  283.     GWorldPtr         dstWorld;
  284.     PixMapHandle         srcPixMap, dstPixMap;
  285.     long                 *srcBaseAddr, *dstBaseAddr, srcRowLongs, dstRowLongs;
  286.     Rect                 srcRect, dstRect;
  287.     mapping             inverseMapping;
  288.     short             x, y, mmuMode;
  289.  
  290.     /*    Create the dstWorld sized to hold the transformed srcWorld
  291.     */
  292.     dstRect = srcRect = srcWorld->portRect;
  293.     MapRectangle(dstMapping, &dstRect);
  294.     if (NewGWorld(&dstWorld, 32, &dstRect, 0, 0, 0))
  295.         return 0;
  296.  
  297.     /*    Optionally, create a maskWorld with the same bounds as the dstWorld
  298.     */
  299.     if (maskWorld)
  300.     {    if (NewGWorld(maskWorld, 1, &dstRect, 0, 0, 0))
  301.         {    DisposeGWorld(dstWorld);
  302.             return 0;
  303.         }
  304.         EraseGWorld(*maskWorld, &dstRect);
  305.     }
  306.  
  307.     /*    Setup for fast walking of the src and dst. Need to swap MMU mode to look at the baseAddr.
  308.     */
  309.     srcPixMap = GetGWorldPixMap( srcWorld );
  310.     dstPixMap = GetGWorldPixMap( dstWorld );
  311.     srcBaseAddr = (long *) GetPixBaseAddr ( srcPixMap );    /* get the address of the pixmap */
  312.     srcRowLongs = ((**srcPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  313.     dstBaseAddr = (long *) GetPixBaseAddr ( dstPixMap );    /* get the address of the pixmap */
  314.     dstRowLongs = ((**dstPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  315.  
  316.     LockPixels(srcPixMap);
  317.     LockPixels(dstPixMap);
  318.  
  319.     inverseMapping = *dstMapping;    
  320.     InvertMapping(&inverseMapping);
  321.     
  322.     mmuMode = true32b;
  323.     SwapMMUMode(&mmuMode);
  324.     for (y = dstRect.top; y < dstRect.bottom; y++)
  325.     {    long* dstAddr = dstBaseAddr;
  326.  
  327.         for (x = dstRect.left; x < dstRect.right; x++)
  328.         {    Fixed srcX = ff(x);
  329.             Fixed srcY = ff(y);
  330.  
  331.             MapXY(&inverseMapping, &srcX, &srcY);
  332.             if (GetFractionalPixel(srcBaseAddr, srcRowLongs, &srcRect, srcX, srcY, dstAddr++) && maskWorld)
  333.                 SetGWorldPixel(*maskWorld, x, y);
  334.         }
  335.         dstBaseAddr += dstRowLongs;
  336.     }
  337.     SwapMMUMode(&mmuMode);
  338.  
  339.     UnlockPixels(srcPixMap);
  340.     UnlockPixels(dstPixMap);
  341.  
  342.     return dstWorld;
  343. }
  344.  
  345. /* Editor's Note: I modified this routine to always use the tent filter, for demo purposes. There's a similar routine
  346. below that uses only the box filter, and the more general routine that's in the article is above */
  347. GWorldPtr MapGWorldTent(GWorldPtr srcWorld, mapping* dstMapping, GWorldPtr* maskWorld)
  348. {
  349.     GWorldPtr         dstWorld;
  350.     PixMapHandle         srcPixMap, dstPixMap;
  351.     long                 *srcBaseAddr, *dstBaseAddr, srcRowLongs, dstRowLongs;
  352.     Rect                 srcRect, dstRect;
  353.     mapping             inverseMapping;
  354.     short             x, y, mmuMode;
  355.  
  356.     /*    Create the dstWorld sized to hold the transformed srcWorld
  357.     */
  358.     dstRect = srcRect = srcWorld->portRect;
  359.     MapRectangle(dstMapping, &dstRect);
  360.     if (NewGWorld(&dstWorld, 32, &dstRect, 0, 0, 0))
  361.         return 0;
  362.  
  363.     /*    Optionally, create a maskWorld with the same bounds as the dstWorld
  364.     */
  365.     if (maskWorld)
  366.     {    if (NewGWorld(maskWorld, 1, &dstRect, 0, 0, 0))
  367.         {    DisposeGWorld(dstWorld);
  368.             return 0;
  369.         }
  370.         EraseGWorld(*maskWorld, &dstRect);
  371.     }
  372.  
  373.     /*    Setup for fast walking of the src and dst. Need to swap MMU mode to look at the baseAddr.
  374.     */
  375.     srcPixMap = GetGWorldPixMap( srcWorld );
  376.     dstPixMap = GetGWorldPixMap( dstWorld );
  377.     srcBaseAddr = (long *) GetPixBaseAddr ( srcPixMap );    /* get the address of the pixmap */
  378.     srcRowLongs = ((**srcPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  379.     dstBaseAddr = (long *) GetPixBaseAddr ( dstPixMap );    /* get the address of the pixmap */
  380.     dstRowLongs = ((**dstPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  381.  
  382.     LockPixels(srcPixMap);
  383.     LockPixels(dstPixMap);
  384.  
  385.     inverseMapping = *dstMapping;    
  386.     InvertMapping(&inverseMapping);
  387.     
  388.     mmuMode = true32b;
  389.     SwapMMUMode(&mmuMode);
  390.     for (y = dstRect.top; y < dstRect.bottom; y++)
  391.     {    long* dstAddr = dstBaseAddr;
  392.  
  393.         for (x = dstRect.left; x < dstRect.right; x++)
  394.         {    Fixed srcX = ff(x);
  395.             Fixed srcY = ff(y);
  396.  
  397.             MapXY(&inverseMapping, &srcX, &srcY);
  398.             if (GetFractionalPixelTent(srcBaseAddr, srcRowLongs, &srcRect, srcX, srcY, dstAddr++) && maskWorld)
  399.                 SetGWorldPixel(*maskWorld, x, y);
  400.         }
  401.         dstBaseAddr += dstRowLongs;
  402.     }
  403.     SwapMMUMode(&mmuMode);
  404.  
  405.     UnlockPixels(srcPixMap);
  406.     UnlockPixels(dstPixMap);
  407.  
  408.     return dstWorld;
  409. }
  410.  
  411. /* Editor's Note: I modified this routine to always use the box filter, for demo purposes. There's a similar routine
  412. above that uses only the tent filter */
  413. GWorldPtr MapGWorldBox(GWorldPtr srcWorld, mapping* dstMapping, GWorldPtr* maskWorld)
  414. {
  415.     GWorldPtr         dstWorld;
  416.     PixMapHandle         srcPixMap, dstPixMap;
  417.     long                 *srcBaseAddr, *dstBaseAddr, srcRowLongs, dstRowLongs;
  418.     Rect                 srcRect, dstRect;
  419.     mapping             inverseMapping;
  420.     short             x, y, mmuMode;
  421.  
  422.     /*    Create the dstWorld sized to hold the transformed srcWorld
  423.     */
  424.     dstRect = srcRect = srcWorld->portRect;
  425.     MapRectangle(dstMapping, &dstRect);
  426.     if (NewGWorld(&dstWorld, 32, &dstRect, 0, 0, 0))
  427.         return 0;
  428.  
  429.     /*    Optionally, create a maskWorld with the same bounds as the dstWorld
  430.     */
  431.     if (maskWorld)
  432.     {    if (NewGWorld(maskWorld, 1, &dstRect, 0, 0, 0))
  433.         {    DisposeGWorld(dstWorld);
  434.             return 0;
  435.         }
  436.         EraseGWorld(*maskWorld, &dstRect);
  437.     }
  438.  
  439.     /*    Setup for fast walking of the src and dst. Need to swap MMU mode to look at the baseAddr.
  440.     */
  441.     srcPixMap = GetGWorldPixMap( srcWorld );
  442.     dstPixMap = GetGWorldPixMap( dstWorld );
  443.     srcBaseAddr = (long *) GetPixBaseAddr ( srcPixMap );    /* get the address of the pixmap */
  444.     srcRowLongs = ((**srcPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  445.     dstBaseAddr = (long *) GetPixBaseAddr ( dstPixMap );    /* get the address of the pixmap */
  446.     dstRowLongs = ((**dstPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  447.  
  448.     LockPixels(srcPixMap);
  449.     LockPixels(dstPixMap);
  450.  
  451.     inverseMapping = *dstMapping;    
  452.     InvertMapping(&inverseMapping);
  453.     
  454.     mmuMode = true32b;
  455.     SwapMMUMode(&mmuMode);
  456.     for (y = dstRect.top; y < dstRect.bottom; y++)
  457.     {    long* dstAddr = dstBaseAddr;
  458.  
  459.         for (x = dstRect.left; x < dstRect.right; x++)
  460.         {    Fixed srcX = ff(x);
  461.             Fixed srcY = ff(y);
  462.  
  463.             MapXY(&inverseMapping, &srcX, &srcY);
  464.             if (GetFractionalPixelBox(srcBaseAddr, srcRowLongs, &srcRect, srcX, srcY, dstAddr++) && maskWorld)
  465.                 SetGWorldPixel(*maskWorld, x, y);
  466.         }
  467.         dstBaseAddr += dstRowLongs;
  468.     }
  469.     SwapMMUMode(&mmuMode);
  470.  
  471.     UnlockPixels(srcPixMap);
  472.     UnlockPixels(dstPixMap);
  473.  
  474.     return dstWorld;
  475. }
  476.  
  477. /* Editor's Note: I modified this routine to always use the fancy mapping (sine wave), for demo purposes. */
  478. GWorldPtr FancyMapGWorld(GWorldPtr srcWorld, mapping* dstMapping, GWorldPtr* maskWorld)
  479. {
  480.     GWorldPtr         dstWorld;
  481.     PixMapHandle         srcPixMap, dstPixMap;
  482.     long                 *srcBaseAddr, *dstBaseAddr, srcRowLongs, dstRowLongs;
  483.     Rect                 srcRect, dstRect;
  484.     mapping             inverseMapping;
  485.     short             x, y, mmuMode;
  486.  
  487.     /*    Create the dstWorld sized to hold the transformed srcWorld
  488.     */
  489.     dstRect = srcRect = srcWorld->portRect;
  490.     MapRectangle(dstMapping, &dstRect);
  491.     FancyMapBounds(&dstRect);
  492.     if (NewGWorld(&dstWorld, 32, &dstRect, 0, 0, 0))
  493.         return 0;
  494.  
  495.     /*    Optionally, create a maskWorld with the same bounds as the dstWorld
  496.     */
  497.     if (maskWorld)
  498.     {    if (NewGWorld(maskWorld, 1, &dstRect, 0, 0, 0))
  499.         {    DisposeGWorld(dstWorld);
  500.             return 0;
  501.         }
  502.         EraseGWorld(*maskWorld, &dstRect);
  503.     }
  504.  
  505.     /*    Setup for fast walking of the src and dst. Need to swap MMU mode to look at the baseAddr.
  506.     */
  507.     srcPixMap = GetGWorldPixMap( srcWorld );
  508.     dstPixMap = GetGWorldPixMap( dstWorld );
  509.     srcBaseAddr = (long *) GetPixBaseAddr ( srcPixMap );    /* get the address of the pixmap */
  510.     srcRowLongs = ((**srcPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  511.     dstBaseAddr = (long *) GetPixBaseAddr ( dstPixMap );    /* get the address of the pixmap */
  512.     dstRowLongs = ((**dstPixMap).rowBytes & 0x7fff) >> 2;    /* get the row increment */
  513.  
  514.     LockPixels(srcPixMap);
  515.     LockPixels(dstPixMap);
  516.  
  517.     inverseMapping = *dstMapping;    
  518.     InvertMapping(&inverseMapping);
  519.     
  520.     mmuMode = true32b;
  521.     SwapMMUMode(&mmuMode);
  522.     for (y = dstRect.top; y < dstRect.bottom; y++)
  523.     {    long* dstAddr = dstBaseAddr;
  524.  
  525.         for (x = dstRect.left; x < dstRect.right; x++)
  526.         {    Fixed srcX = ff(x);
  527.             Fixed srcY = ff(y);
  528.  
  529.             MapXY(&inverseMapping, &srcX, &srcY);
  530.             FancyMap(&srcRect, &srcX, &srcY);
  531.             if (GetFractionalPixelBox(srcBaseAddr, srcRowLongs, &srcRect, srcX, srcY, dstAddr++) && maskWorld)
  532.                 SetGWorldPixel(*maskWorld, x, y);
  533.         }
  534.         dstBaseAddr += dstRowLongs;
  535.     }
  536.     SwapMMUMode(&mmuMode);
  537.  
  538.     UnlockPixels(srcPixMap);
  539.     UnlockPixels(dstPixMap);
  540.  
  541.     return dstWorld;
  542. }
  543.  
  544. GWorldPtr PictToGWorld( PicHandle pict, Rect* bounds )
  545. {
  546.     GWorldPtr world;
  547.     short err;
  548.  
  549.     *bounds = (*pict)->picFrame;
  550.     OffsetRect(bounds, -bounds->left, -bounds->top);
  551.  
  552.     if (!(err = NewGWorld(&world, 32, bounds, 0, 0, 0)))
  553.     {    GDHandle oldGD;
  554.         GWorldPtr oldGW;
  555.  
  556.         GetGWorld(&oldGW,&oldGD);
  557.         SetGWorld(world,nil);
  558.         EraseRect( bounds );
  559.         DrawPicture( pict, bounds);
  560.         SetGWorld(oldGW,oldGD);
  561.  
  562.         return world;
  563.     }
  564.     else
  565.         return nil;
  566. }
  567.  
  568. void CenterRect(Rect* r, short x, short y)
  569. {
  570.     OffsetRect(r, x - (r->right + r->left >> 1), y - (r->bottom + r->top >> 1));
  571. }
  572.